﻿using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
using PmSoft.Core.Extensions;

namespace PmSoft.Core.Reflection;

/// <summary>
/// 反射类型上下文
/// </summary>
public sealed class ReflectionContext
{
	/// <summary>
	/// 初始化 ReflectionContext 类的新实例
	/// </summary>
	/// <param name="type">类型</param>
	public ReflectionContext(Type type)
	{
		Type = type;
		Name = type.Name;
		TypeInfo = type.GetTypeInfo();
		FullName = type.FullName;
		Assembly = type.Assembly;

		Attributes = type.GetCustomAttributes().ToArray();

		Fields = type.GetFields().Where(x => !x.IsStatic).Select(member => new FieldInfoExplorer(type, member)).ToArray();
		Members = type.GetMembers().Select(member => new MemberInfoExplorer(member)).ToArray();
		Methods = type.GetMethods().Select(member => new MethodInfoExplorer(member)).ToArray();
		Properties = type.GetProperties().Select(member => new PropertyInfoExplorer(type, member)).ToArray();
		IsValueType = TypeInfo.IsValueType;
		Constructors = TypeInfo.GetConstructors().Select(x => new ConstructorExplorer(x)).ToArray();
	}

	/// <summary>
	/// 获取类型
	/// </summary>
	public Type Type { get; }

	/// <summary>
	/// 获取程序集
	/// </summary>
	public Assembly Assembly { get; }

	/// <summary>
	/// 获取类型名称
	/// </summary>
	public string Name { get; }

	/// <summary>
	/// 获取类型全名
	/// </summary>
	public string? FullName { get; }

	/// <summary>
	/// 获取类型信息
	/// </summary>
	public TypeInfo TypeInfo { get; }

	/// <summary>
	/// 获取类型的特性
	/// </summary>
	public Attribute[] Attributes { get; }

	/// <summary>
	/// 获取类型是否为值类型
	/// </summary>
	public bool IsValueType { get; }

	/// <summary>
	/// 获取类型的构造函数
	/// </summary>
	public ConstructorExplorer[] Constructors { get; }

	/// <summary>
	/// 获取类型的字段
	/// </summary>
	public FieldInfoExplorer[] Fields { get; }

	/// <summary>
	/// 获取类型的成员
	/// </summary>
	public MemberInfoExplorer[] Members { get; }

	/// <summary>
	/// 获取类型的方法
	/// </summary>
	public MethodInfoExplorer[] Methods { get; }

	/// <summary>
	/// 获取类型的属性
	/// </summary>
	public PropertyInfoExplorer[] Properties { get; }

	/// <summary>
	/// 获取类型的指定特性
	/// </summary>
	/// <typeparam name="TAttr">特性类型</typeparam>
	/// <returns>特性实例</returns>
	public TAttr? GetAttribute<TAttr>() where TAttr : Attribute
	{
		return Attributes.OfType<TAttr>().FirstOrDefault();
	}

	/// <summary>
	/// 获取类型的所有指定特性
	/// </summary>
	/// <typeparam name="TAttr">特性类型</typeparam>
	/// <returns>特性实例集合</returns>
	public IEnumerable<TAttr> GetAttributes<TAttr>() where TAttr : Attribute
	{
		return Attributes.OfType<TAttr>();
	}
}

/// <summary>
/// 构造函数信息
/// </summary>
public class ConstructorExplorer
{
	/// <summary>
	/// 初始化 ConstructorExplorer 类的新实例
	/// </summary>
	/// <param name="ctor">构造函数信息</param>
	public ConstructorExplorer(ConstructorInfo ctor)
	{
		Constructor = ctor;
		Parameters = ctor.GetParameters();
	}

	/// <summary>
	/// 获取构造函数的参数信息
	/// </summary>
	public ParameterInfo[] Parameters { get; }

	/// <summary>
	/// 获取构造函数信息
	/// </summary>
	public ConstructorInfo Constructor { get; }
}

/// <summary>
/// 类型成员信息基类
/// </summary>
/// <typeparam name="T">成员类型</typeparam>
public abstract class TypeMemberExplorer<T> where T : MemberInfo
{
	protected TypeMemberExplorer(T member)
	{
		Name = member.Name;
		Member = member;
		Attributes = member.GetCustomAttributes().ToArray();
		MemberType = member.MemberType;
	}

	/// <summary>
	/// 获取成员的指定特性
	/// </summary>
	/// <typeparam name="TAttr">特性类型</typeparam>
	/// <returns>特性实例</returns>
	public TAttr? GetAttribute<TAttr>() where TAttr : Attribute
	{
		return Attributes.OfType<TAttr>().FirstOrDefault();
	}

	/// <summary>
	/// 获取成员的所有指定特性
	/// </summary>
	/// <typeparam name="TAttr">特性类型</typeparam>
	/// <returns>特性实例集合</returns>
	public IEnumerable<TAttr> GetAttributes<TAttr>() where TAttr : Attribute
	{
		return Attributes.OfType<TAttr>();
	}

	/// <summary>
	/// 获取成员的特性
	/// </summary>
	public Attribute[] Attributes { get; }

	/// <summary>
	/// 获取成员类型
	/// </summary>
	public MemberTypes MemberType { get; }

	/// <summary>
	/// 获取成员信息
	/// </summary>
	public T Member { get; }

	/// <summary>
	/// 获取成员名称
	/// </summary>
	public string Name { get; }

	/// <summary>
	/// 类型成员信息上下文
	/// </summary>
	protected sealed class TypeMemberExplorerContext
	{
		public Delegate Getter { get; set; }
		public Delegate Setter { get; set; }
	}
}

/// <summary>
/// 成员信息
/// </summary>
public class MemberInfoExplorer : TypeMemberExplorer<MemberInfo>
{
	public MemberInfoExplorer(MemberInfo member) : base(member)
	{
	}
}

/// <summary>
/// 属性信息
/// </summary>
public class PropertyInfoExplorer : TypeMemberExplorer<PropertyInfo>
{
	private static readonly ConcurrentDictionary<PropertyInfo, TypeMemberExplorerContext> _typeFn = new();
	private readonly Type _type;

	public PropertyInfoExplorer(Type type, PropertyInfo member) : base(member)
	{
		_type = type;
		IsNullable = member.IsNullable();
		ExpressionModel = new PropertyExpressionModel(member);
	}

	/// <summary>
	/// 获取表达式模型
	/// </summary>
	public IMemberExpressionModel ExpressionModel { get; }

	/// <summary>
	/// 获取属性是否可空
	/// </summary>
	public bool IsNullable { get; }

	/// <summary>
	/// 获取属性值
	/// </summary>
	/// <param name="v">对象实例</param>
	/// <returns>属性值</returns>
	public object? GetValue(object v) => Member.GetValue(v);

	/// <summary>
	/// 设置属性值
	/// </summary>
	/// <param name="v">对象实例</param>
	/// <param name="value">属性值</param>
	public void SetValue(object v, object value) => Member.SetValue(v, value);

	/// <summary>
	/// 获取属性值
	/// </summary>
	/// <typeparam name="T">对象类型</typeparam>
	/// <typeparam name="TValue">属性值类型</typeparam>
	/// <param name="v">对象实例</param>
	/// <returns>属性值</returns>
	public TValue GetValue<T, TValue>(T v) where T : class
	{
		var ctx = GetOrCreateContext<T, TValue>();
		var invoker = (Func<T, TValue>)ctx.Getter;
		return invoker(v);
	}

	/// <summary>
	/// 设置属性值
	/// </summary>
	/// <typeparam name="T">对象类型</typeparam>
	/// <typeparam name="TValue">属性值类型</typeparam>
	/// <param name="v">对象实例</param>
	/// <param name="value">属性值</param>
	public void SetValue<T, TValue>(T v, TValue? value) where T : class
	{
		var ctx = GetOrCreateContext<T, TValue>();
		if (ctx.Setter != null)
		{
			var invoker = (Action<T, TValue?>)ctx.Setter;
			invoker(v, value);
		}
	}

	private TypeMemberExplorerContext GetOrCreateContext<T, TValue>()
	{
		return _typeFn.GetOrAdd(Member, x =>
		{
			var context = new TypeMemberExplorerContext();
			var getter = BuildGetter<T, TValue>();
			context.Getter = Expression.Lambda<Func<T, TValue>>(getter.Item2, getter.Item1).Compile();

			if (Member.CanWrite)
			{
				var setter = BuildSetter<T, TValue>();
				context.Setter = Expression.Lambda<Action<T, TValue>>(setter.Item1, setter.Item2, setter.Item3).Compile();
			}

			return context;
		});
	}

	private (Expression, ParameterExpression, ParameterExpression) BuildSetter<T, TValue>()
	{
		var source = Expression.Parameter(typeof(T), "source");
		var parameter = Expression.Parameter(typeof(TValue));
		var property = ExpressionModel.GetExpression(source);
		Expression setter;
		if (typeof(TValue) != Member.PropertyType)
			setter = Expression.Assign(property, Expression.Convert(parameter, Member.PropertyType));
		else
			setter = Expression.Assign(property, parameter);
		return (setter, source, parameter);
	}

	private (ParameterExpression, Expression) BuildGetter<T, TValue>()
	{
		var source = Expression.Parameter(typeof(T), "source");
		var property = ExpressionModel.GetExpression(source);
		if (typeof(TValue) != Member.PropertyType)
			property = Expression.Convert(property, typeof(TValue));
		return (source, property);
	}
}

/// <summary>
/// 字段信息
/// </summary>
public class FieldInfoExplorer : TypeMemberExplorer<FieldInfo>
{
	private static readonly ConcurrentDictionary<FieldInfo, TypeMemberExplorerContext> _typeFn = new();
	private readonly Type _type;

	public FieldInfoExplorer(Type type, FieldInfo member) : base(member)
	{
		_type = type;
		IsNullable = member.IsNullable();
		ExpressionModel = new FieldExpressionModel(member);
	}

	/// <summary>
	/// 获取表达式模型
	/// </summary>
	public IMemberExpressionModel ExpressionModel { get; }

	/// <summary>
	/// 获取字段是否可空
	/// </summary>
	public bool IsNullable { get; }

	/// <summary>
	/// 获取字段值
	/// </summary>
	/// <param name="v">对象实例</param>
	/// <returns>字段值</returns>
	public object? GetValue(object v) => Member.GetValue(v);

	/// <summary>
	/// 获取字段值
	/// </summary>
	/// <typeparam name="T">对象类型</typeparam>
	/// <typeparam name="TValue">字段值类型</typeparam>
	/// <param name="v">对象实例</param>
	/// <returns>字段值</returns>
	public TValue GetValue<T, TValue>(T v) where T : class
	{
		var ctx = GetOrCreateContext<T, TValue>();
		var invoker = (Func<T, TValue>)ctx.Getter;
		return invoker(v);
	}

	/// <summary>
	/// 设置字段值
	/// </summary>
	/// <typeparam name="T">对象类型</typeparam>
	/// <typeparam name="TValue">字段值类型</typeparam>
	/// <param name="v">对象实例</param>
	/// <param name="value">字段值</param>
	public void SetValue<T, TValue>(T v, TValue value) where T : class
	{
		var ctx = GetOrCreateContext<T, TValue>();
		var invoker = (Action<T, TValue>)ctx.Setter;
		invoker(v, value);
	}

	private TypeMemberExplorerContext GetOrCreateContext<T, TValue>()
	{
		return _typeFn.GetOrAdd(Member, x =>
		{
			var getter = BuildGetter<T, TValue>();
			var context = new TypeMemberExplorerContext
			{
				Getter = Expression.Lambda<Func<T, TValue>>(getter.Item1, getter.Item2).Compile()
			};

			var setter = BuildSetter<T, TValue>();
			context.Setter = Expression.Lambda<Action<T, TValue>>(setter.Item1, setter.Item2, setter.Item3).Compile();

			return context;
		});
	}

	private (Expression, ParameterExpression, ParameterExpression) BuildSetter<T, TValue>()
	{
		var parameter = Expression.Parameter(typeof(TValue));
		Expression setter;
		ParameterExpression source;
		if (typeof(T) == typeof(object))
		{
			source = Expression.Parameter(typeof(object));
			var castSource = Expression.Convert(source, _type);

			var getter = ExpressionModel.GetExpression(castSource);
			setter = Expression.Assign(getter, typeof(TValue) != Member.FieldType ? Expression.Convert(parameter, Member.FieldType) : parameter);
		}
		else
		{
			source = Expression.Parameter(_type, "source");
			var getter = ExpressionModel.GetExpression(source);
			setter = Expression.Assign(getter, typeof(TValue) != Member.FieldType ? Expression.Convert(parameter, Member.FieldType) : parameter);
		}

		return (setter, source, parameter);
	}

	private (Expression, ParameterExpression) BuildGetter<T, TValue>()
	{
		Expression getter;
		ParameterExpression source;
		if (typeof(T) == typeof(object))
		{
			source = Expression.Parameter(typeof(object));
			var castSource = Expression.Convert(source, _type);
			getter = ExpressionModel.GetExpression(castSource);
		}
		else
		{
			source = Expression.Parameter(typeof(T), "source");
			getter = ExpressionModel.GetExpression(source);
		}
		if (typeof(TValue) != Member.FieldType)
			getter = Expression.Convert(getter, typeof(TValue));
		return (getter, source);
	}
}

/// <summary>
/// 方法信息
/// </summary>
public class MethodInfoExplorer : TypeMemberExplorer<MethodInfo>
{
	public MethodInfoExplorer(MethodInfo member) : base(member)
	{
		Parameters = member.GetParameters();
	}

	/// <summary>
	/// 获取方法的参数信息
	/// </summary>
	public ParameterInfo[] Parameters { get; }
}


